package com.xhwl.centiotdata.handler.alarm.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xhwl.centiotdata.handler.alarm.AlarmHandler;
import com.xhwl.centiotdata.pushtrigger.alarm.subscribe.IVS3800Subscribe;
import com.xhwl.centiotdata.service.alarm.SubsystemPushService;
import com.xhwl.centiotdata.service.integrateconfig.AlarmIntegrationConfig;
import com.xhwl.centiotdata.utils.RedisUtils;
import com.xhwl.centiotdata.utils.ThreadPoolUtils;
import com.xhwl.centiotdata.utils.UploadUtils;
import com.xhwl.common.constant.cent.alarm.AlarmConstant;
import com.xhwl.common.dto.cent.alarm.AlarmIntegrationConfigDTO;
import com.xhwl.common.dto.cent.alarm.AlarmOrgMessageDTO;
import com.xhwl.common.dto.cent.alarm.haiwei3800.AlarmContent;
import com.xhwl.common.dto.cent.alarm.haiwei3800.AlarmSnapshotListResult;
import com.xhwl.common.dto.cent.alarm.haiwei3800.SubscribeNotifications;
import com.xhwl.common.dto.cent.alarm.haiwei3800.ViidApeSubResult;
import com.xhwl.common.dto.cent.device.DeviceDTO;
import com.xhwl.common.enums.ProductEnum;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.alarm.AlarmLog;
import com.xhwl.common.pojo.cent.alarm.AlarmManagement;
import com.xhwl.common.query.cent.device.DevicePageQuery;
import com.xhwl.common.utils.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author Leon
 * @Description: TODO
 * @Date: 2022/5/16 9:51
 */
@Component
@Slf4j
public class AlarmHuaWeiH3800Handler extends AlarmHandler {

    @Autowired
    AlarmIntegrationConfig alarmIntegrationConfig;

    @Autowired
    SubsystemPushService subsystemPushService;

    @Override
    public void afterPropertiesSet() throws Exception {
        //AlarmFactory.register("AccessInformation",this);
    }

    public ResultJson huaWeiH3800Receive(String receiveBody, Integer rowId) {
        log.info("====收到 ivs3800 告警数据 === rowId: {}", rowId);
        AlarmLog alarmLog = new AlarmLog();
        alarmLog.setTag("huawei_ivs3800_alarm");
        alarmLog.setContent(receiveBody);
        alarmLog.setPushTime(new Date());
        centAlarmService.insert(alarmLog);
        Map<String, String> entries = redisTemplate.opsForHash().entries(RedisUtils.format(ProductEnum.HUAWEI_IVS3800.getId()));
        JSONObject jsonObject = JSONObject.parseObject(receiveBody);
        AlarmContent alarmContent = XMLUtil.convertXmlStrToObject(AlarmContent.class, jsonObject.get("eventData").toString());
        AlarmIntegrationConfigDTO alarmIntegrationConfigDTO = alarmIntegrationConfig.getIntegrationConfigById(rowId);
        String alarmType = alarmContent.getAlarmType();
        log.info("3800 告警信息 alarmType: {}  thirdDeviceId: {}", alarmType, alarmContent.getAlarmInCode());
        if (StringUtils.isNotBlank(entries.get(alarmType))) {
            String inventoryCode = entries.get(alarmType);
            DevicePageQuery devicePageQuery = new DevicePageQuery();
            List<AlarmIntegrationConfigDTO.AlarmDevicesMap> alarmDevicesMapList = alarmIntegrationConfigDTO.getAlarmDevicesMapList();
            // 处理3800 特殊告警事件，告警源不是摄像头，没有同步这类设备，做映射处理
            if (CollectionUtils.isNotEmpty(alarmDevicesMapList)) {
                for (AlarmIntegrationConfigDTO.AlarmDevicesMap alarmDevicesMap : alarmDevicesMapList) {
                    List<String> alarmDevicesEvents = alarmDevicesMap.getAlarmDevicesEvents();
                    if (CollectionUtils.isNotEmpty(alarmDevicesEvents) && Objects.equals(alarmDevicesEvents.get(0), alarmType)) {
                        String cameraCode = "";
                        inventoryCode = alarmDevicesEvents.get(1);
                        List<AlarmIntegrationConfigDTO.CameraMap> cameraMap = alarmDevicesMap.getCameraMap();
                        for (AlarmIntegrationConfigDTO.CameraMap map: cameraMap) {
                            if (map.getSourceCodes().contains(alarmContent.getAlarmInCode())) {
                                cameraCode = map.getCameraCode();
                                break;
                            }
                        }
                        if (StringUtils.isBlank(cameraCode)) {
                            throw new DataException(String.format("=====3800 告警设备未配置 AlarmInCode: %s====", alarmContent.getAlarmInCode()));
                        }
                        devicePageQuery.setThirdDeviceId(cameraCode);
                    }
                }
            } else {
                devicePageQuery.setThirdDeviceId(alarmContent.getAlarmInCode());
            }
            devicePageQuery.setProductId(ProductEnum.HUAWEI_IVS3800.getId());
            devicePageQuery.setProjectId(alarmIntegrationConfigDTO.getProjectId());
            Page<DeviceDTO> deviceDTOPage = deviceCentService.pageDevice(null, devicePageQuery);
            DeviceDTO deviceDTO = Optional.ofNullable(deviceDTOPage).map(Page::getRecords)
                    .filter(item -> CollectionUtils.isNotEmpty(item))
                    .map(item -> item.get(0)).orElseThrow(() -> new DataException("====================》设备不存在《================"));
            AlarmManagement alarmManagement = new AlarmManagement();
            // 延迟为了获取告警图片
            String alarmInventoryCode = inventoryCode;
            ThreadPoolUtils.scheduledExecutorService.schedule(() -> {
                String token = alarmIntegrationConfigDTO.getToken();
                if (!StringUtils.isEmpty(token)) {
                    Integer eventId = Integer.valueOf(alarmContent.getAlarmEventId());
                    String cameraCode = alarmContent.getAlarmInCode();

                    try {
                        AlarmSnapshotListResult snapshotListResult = IVS3800Subscribe.getAlarmSnapshotList(
                                alarmIntegrationConfigDTO, eventId, cameraCode);
                        List<AlarmSnapshotListResult.SnapInfo> snapShotList = snapshotListResult.getSnapShotList();
                        String picUrl = "";
                        if (CollectionUtils.isNotEmpty(snapShotList)) {
                            picUrl = snapShotList.get(0).getPictureUrl();
                        }
                        if (StringUtils.isNoneBlank(picUrl)) {
                            String pictureUrl = UploadUtils.uploadImg(picUrl);
                            alarmManagement.setImgUrl(pictureUrl);
                        } else {
                            log.info("3800告警不含图片 {} {}", alarmContent.getAlarmInCode(), alarmContent.getAlarmEventId());
                        }
                    } catch (Exception e) {
                        log.error("3800告警图片上传失败====================>alarmInCode:{}======>alarmEventId:{}",
                                alarmContent.getAlarmInCode(), alarmContent.getAlarmEventId());
                        log.error("请求参数为===============》{}", eventId);
                        log.error("异常为===========》{}", e);
                    }
                } else {
                    log.error("3800 token 不存在");
                }
                alarmManagement.setAlarmTime(new Date());
                alarmManagement.setDeviceId(deviceDTO.getId());
                alarmManagement.setProjectId(deviceDTO.getProjectId());
                alarmManagement.setAlarmInventoryCode(alarmInventoryCode);
                sendMq(AlarmConstant.IVS3800_ALARM_TOPIC, alarmManagement);
                subsystemPushService.sendAlarmPush(alarmManagement, alarmIntegrationConfigDTO);
            }, 5, TimeUnit.SECONDS);
        } else {
            log.error("ivs3800 厂商告警类型未配置 InventoryCode : {}", alarmType);
        }
        return ResultJson.success();
    }


    public ResultJson huaweiH3800IntelligenceReceive(String receiveBody) {
        log.info("====收到 ivs3800 智能数据 ===");
        SubscribeNotifications subscribeNotifications = JSONObject.parseObject(receiveBody, SubscribeNotifications.class);

        SubscribeNotifications.SubscribeNotificationListObject subscribeNotificationListObject = Optional.ofNullable(subscribeNotifications)
                .map(i -> i.getSubscribeNotificationListObject())
                .orElse(null);
        SubscribeNotifications.DispositionNotificationListObject dispositionNotificationListObject = Optional.ofNullable(subscribeNotifications)
                .map(i -> i.getDispositionNotificationListObject())
                .orElse(null);

        if (Objects.nonNull(subscribeNotificationListObject)) {
            log.info("收到 ivs 3800 智能元数据");
            sendIvsSubscribeData(subscribeNotifications);
        }

        if (Objects.nonNull(dispositionNotificationListObject)) {
            log.info("收到 ivs 3800 智能告警数据");
            sendIvsDispositionData(subscribeNotifications);
        }

        return ResultJson.success();
    }

    private void sendIvsSubscribeData(SubscribeNotifications subscribeNotifications) {
        SubscribeNotifications.SubscribeNotification notification = Optional.ofNullable(subscribeNotifications)
                .map(i -> i.getSubscribeNotificationListObject())
                .map(i -> i.getSubscribeNotificationObject())
                .filter(i -> CollectionUtils.isNotEmpty(i))
                .map(i -> i.get(0))
                .orElseThrow(() -> new DataException("=====ivs3800 智能数据 无数据===="));

        String notificationID = Optional.ofNullable(notification)
                .map(i -> i.getNotificationID())
                .orElseThrow(() -> new DataException("=====ivs3800 智能数据 无通知标识 无效数据===="));
        log.info("==============ivs3800 智能元数据 notificationID: {}", notificationID);

        String infoIDs = Optional.ofNullable(notification)
                .map(i -> i.getInfoIDs()).orElseThrow(() -> new DataException("================》ivs3800 智能数据 InfoIDs为空"));
        log.info("==============ivs3800 智能元数据 InfoIDs: {}", infoIDs);

        List<SubscribeNotifications.MotorVehicle> motorVehicleList = Optional.ofNullable(notification)
                .map(i -> i.getMotorVehicleObjectList())
                .map(i -> i.getMotorVehicleObject())
                .orElse(new ArrayList<>());

        Integer projectId = null;
        String cameraCode = "";
        String connectCode = "";

        {
            connectCode = Optional.ofNullable(motorVehicleList)
                    .filter(i -> CollectionUtils.isNotEmpty(i))
                    .map(i -> i.get(0))
                    .map(i -> i.getDeviceID())
                    .orElse(null);
        }

        if (StringUtils.isEmpty(connectCode)) {
            throw new DataException("ivs 3800 智能数据" + infoIDs + " 获取 connectCode 失败");
        }

        DeviceDTO deviceDTO = getDeviceByConnectCode(connectCode);
        projectId = deviceDTO.getProjectId();
        cameraCode = deviceDTO.getThirdDeviceId();

        AlarmIntegrationConfigDTO alarmIntegrationConfigDTO = getAlarmIntegrationConfig(projectId, cameraCode);
        if (Objects.isNull(alarmIntegrationConfigDTO)) {
            log.error("ivs 3800 智能数据 匹配集成配置失败，projectId: {}, cameraCode: {}", projectId, cameraCode);
            return;
        }

        AlarmOrgMessageDTO alarmOrgMessageDTO = new AlarmOrgMessageDTO();
        alarmOrgMessageDTO.setProjectId(alarmIntegrationConfigDTO.getProjectId());
        alarmOrgMessageDTO.setProductId(ProductEnum.HUAWEI_IVS3800.getId());
        alarmOrgMessageDTO.setContent(JSONObject.toJSONString(subscribeNotifications));
        alarmOrgMessageDTO.setAlarmIntegrationConfigDTO(alarmIntegrationConfigDTO);
        sendMq(AlarmConstant.IVS3800_INTELLIGENCE_TOPIC, alarmOrgMessageDTO);
        log.info("====推送 ivs3800 智能数据 到 kafka 成功 ===");
    }

    private void sendIvsDispositionData(SubscribeNotifications subscribeNotifications) {}

    private AlarmIntegrationConfigDTO getAlarmIntegrationConfig(Integer projectId, String cameraCode) {
        AlarmIntegrationConfigDTO alarmIntegrationConfigDTO = null;
        List<AlarmIntegrationConfigDTO> configDTOList = alarmIntegrationConfig.getIntegrationProductConfig(projectId, ProductEnum.HUAWEI_IVS3800.getId());
        if (CollectionUtils.isEmpty(configDTOList)) {
            log.error("ivs 3800 智能数据 获取集成配置为空，projectId: {}", projectId);
            return null;
        } else if (Objects.equals(configDTOList.size(), 1)) {
            alarmIntegrationConfigDTO = configDTOList.get(0);
        } else {
            ViidApeSubResult.ApeInfo apeInfo = null;
            for (AlarmIntegrationConfigDTO configDTO : configDTOList) {
                ViidApeSubResult.ApeInfo info = IVS3800Subscribe.getViidApeSub(configDTO, cameraCode);
                if (ObjectUtils.isNotEmpty(info)) {
                    apeInfo = info;
                    alarmIntegrationConfigDTO = configDTO;
                    break;
                }
            }
            if (Objects.isNull(apeInfo)) {
                log.error("ivs 3800 智能数据 匹配集成配置失败，projectId: {}, cameraCode: {}", projectId, cameraCode);
                return null;
            }
        }
        return alarmIntegrationConfigDTO;
    }

    private DeviceDTO getDeviceByConnectCode(String connectCode) {
        DevicePageQuery devicePageQuery = new DevicePageQuery();
        devicePageQuery.setIotDeviceId(connectCode);
        devicePageQuery.setProductId(ProductEnum.HUAWEI_IVS3800.getId());
        Page<DeviceDTO> deviceDTOPage = deviceCentService.pageDevice(null, devicePageQuery);
        DeviceDTO deviceDTO = Optional.ofNullable(deviceDTOPage).map(Page::getRecords)
                .filter(item -> CollectionUtils.isNotEmpty(item))
                .map(item -> item.get(0)).orElseThrow(() -> new DataException("====================》ivs3800 智能数据设备不存在《================"));
        return deviceDTO;
    }
}
